import { SideChannelManager } from "./SideChannels/SideChannelManager";
import { StatsSideChannel } from "./SideChannels/StatsSideChannel";


/**
 * @en
 * Determines the behavior of how multiple stats within the same summary period are combined.
 * 
 * @zh
 * 确定如何组合同一摘要周期内的多个统计信息的行为。
 */
export enum StatAggregationMethod {

    /**
     * @en
     * Values within the summary period are averaged before reporting.
     * 
     * @zh
     * 在报告之前，摘要周期内的值将被平均。
     */
    Average = 0,

    /**
     * 
     * @en
     * Only the most recent value is reported.
     * To avoid conflicts when training with multiple concurrent environments, only
     * stats from worker index 0 will be tracked.
     * 
     * @zh
     * 仅报告最新值。
     * 为了避免在使用多个并发环境进行训练时出现冲突，只会跟踪来自 worker 索引 0 的统计信息。
     * 
     */
    MostRecent = 1,

    /**
     * @en
     * Values within the summary period are summed up before reporting.
     * 
     * @zh
     * 在报告之前，摘要周期内的值将被累加。
     */
    Sum = 2,

    /**
     * @en
     * Values within the summary period are reported as a histogram.
     * 
     * @zh
     * 在报告之前，摘要周期内的值将作为直方图报告。
     */
    Histogram = 3
}

/**
 * @en
 *  Add stats (key-value pairs) for reporting. These values will sent these to a StatsReporter
 * instance, which means the values will appear in the TensorBoard summary, as well as trainer
 * gauges. You can nest stats in TensorBoard by adding "/" in the name (e.g. "Agent/Health"
 * and "Agent/Wallet"). Note that stats are only written to TensorBoard each summary_frequency
 * steps (a trainer configuration). If a stat is received multiple times, within that period
 * then the values will be aggregated using the {@link StatAggregationMethod} provided.
 * 
 * @zh
 * 添加用于报告的统计信息（键值对）。这些值将被发送到 StatsReporter 实例，这意味着这些值将出现在 TensorBoard 摘要中，以及训练器计量表中。
 * 您可以通过在名称中添加“/”来在 TensorBoard 中嵌套统计信息（例如“Agent/Health”和“Agent/Wallet”）。
 * 请注意，统计信息仅在每个摘要频率步骤（训练器配置）中写入到 TensorBoard。如果在该期间内多次接收到统计信息，则将使用提供的 {@link StatAggregationMethod} 聚合值。
 * 
 */
export class StatsRecorder {
    private _channel: StatsSideChannel;

    constructor() {
        this._channel = new StatsSideChannel();
        SideChannelManager.registerSideChannel(this._channel);
    }

    /**
     * @en
     * Add a stat value for reporting.
     * 
     * @zh
     * 添加一个用于报告的统计值。
     * 
     * @param key The stat name.
     * @param value the stat value.You can nest stats in TensorBoard by user "/"
     * @param aggregationMethod How multiple values sent in the same summary window should be treated.
     */
    public add(
        key: string,
        value: number,
        aggregationMethod: StatAggregationMethod = StatAggregationMethod.Average
    ): void {
        this._channel.addStat(key, value, aggregationMethod);
    }

    public dispose(): void {
        SideChannelManager.unregisterSideChannel(this._channel);
    }
}